package character;

import action.Action;
import com.jme3.bullet.collision.shapes.CollisionShape;
import board.BoardUtil;
import board.PatternType;
import game.combat.ResolutionListener;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import misc.Vector3i;

public class CharacterCombatControl extends MyCharacterControl implements ResolutionListener {
    protected Set<Vector3i> validMoveLocations = new HashSet<Vector3i>();
    protected boolean attackOfOpportunity = true;
    protected int ticksUsed = 0;
    protected boolean markedForTemporaryResolutionListenerRemoval = false;

    @Deprecated
    protected CharacterCombatControl() {}
    
    public CharacterCombatControl(CollisionShape collisionShape) {
        super(collisionShape);
    }
    
    @Override
    public boolean tick() {
        boolean tickSuccessful = super.tick();
        if(!queuedActions.isEmpty()) { //remove all completed actions from the front of the queue
            Iterator<Action> iter = queuedActions.iterator();
            while(iter.hasNext()) {
                Action action = iter.next();
                if(action.isCompleted()) {
                    if(action.isOffTurnAction()) {
                        markedForTemporaryResolutionListenerRemoval = true;
                    }
                    queuedActions.remove(action);
		    repopulateValidMoveLocations();
                } else {
                    return tickSuccessful;
                }
            }
        }
        return tickSuccessful;
    }

    @Override
    public void resolutionStarted() {
	if(hasQueuedAction()) {
            Action queuedAction = queuedActions.peekFirst();
            if(queuedAction.isStarted() && !queuedAction.isCompleted())
                queuedAction.unpause();
        }
    }

    @Override
    public void resolutionEnded() {
	if(hasQueuedAction()) {
            Action queuedAction = queuedActions.peekFirst();
            if(queuedAction.isStarted() && !queuedAction.isCompleted())
                queuedAction.pause();
        }
    }
    
    @Override
    public Collection<Vector3i> getValidMoveLocations() {
        if(validMoveLocations.isEmpty())
            repopulateValidMoveLocations();
        return validMoveLocations;
    }
    @Override
    public void repopulateValidMoveLocations() {
	validMoveLocations.clear();
        int ticksRemaining = myCharacter.getCharacterStatus().getTicksPerTurn() - getTicksUsed();
        if(hasQueuedAction() && peekQueuedAction().isStarted() && !peekQueuedAction().isCompleted() && peekQueuedAction().getTicksRemaining() > 0)
            ticksRemaining -= peekQueuedAction().getTicksRemaining(); //compensate for a currently queued action which is yet incomplete
        int maxTileMoves = ticksRemaining / myCharacter.getCharacterStats().getMoveSpeedWithModifier();
        if(maxTileMoves > 0) {
            int cardinalSpeed = myCharacter.getCharacterStats().getMoveSpeedWithModifier();
            int diagonalSpeed = myCharacter.getCharacterStats().getDiagonalMoveSpeedWithModifier();
            for(Vector3i occupiedLocation : myCharacter.getOccupiedLocations()) {
                Collection<Vector3i> validLocations = BoardUtil.getPatternLocations(PatternType.SQUARE, maxTileMoves, false, occupiedLocation);
                validLocations.removeAll(validMoveLocations);
                Iterator<Vector3i> iter = validLocations.iterator();
                while(iter.hasNext()) {
                    //TODO needs to use a different method to figure this out (one that can actually factor in walls, etc.)
                    //(or find the cost of the whole path between occupiedLocation and iter.next() and toss it if it's too high)
                    //(but that seems costly. some algorithm which spreads outward from occupiedLocation seems better)
                    if(BoardUtil.costBetween(occupiedLocation, iter.next(), cardinalSpeed, diagonalSpeed) > ticksRemaining)
                        iter.remove();
                }
                validMoveLocations.addAll(validLocations);
            }
            validMoveLocations.removeAll(myCharacter.getOccupiedLocations());
        }
    }
    
    @Override
    public int getTicksUsed() {
	return ticksUsed;
    }
    public void setTicksUsed(int ticksUsed) {
        this.ticksUsed = ticksUsed;
        repopulateValidMoveLocations();
    }
    public void addTicksUsed(int ticks) {
        ticksUsed += ticks;
        repopulateValidMoveLocations();
    }

    public void setAttackOfOpportunity(boolean attackOfOpportunity) {
        this.attackOfOpportunity = attackOfOpportunity;
    }
    public boolean hasAttackOfOpportunity() {
	return attackOfOpportunity;
    }
    public void useAttackOfOpportunity() {
        attackOfOpportunity = false;
    }

    @Override
    public boolean isMarkedForTemporaryResolutionListenerRemoval() {
	return markedForTemporaryResolutionListenerRemoval;
    }
    @Override
    public void setMarkedForTemporaryResolutionListenerRemoval(boolean markedForTemporaryResolutionListenerRemoval) {
	this.markedForTemporaryResolutionListenerRemoval = markedForTemporaryResolutionListenerRemoval;
    }
}
